#pragma once
#include "../core/nodes/feature.h"
#include "argentry.h"
#include <map>
#include "fixclients.h"
#include "parentdata.h"
#include "../templates/hstringlist.h"
#include "../code/methodcode.h"

class SemanticVisitorData;



inline bool contains(const std::vector<ArgEntry> & v,const std::string & s)
{
	for (unsigned int i=0;i<v.size();i++)
		if (s==v[i].Name)
			return true;
	return false;
}

struct Method
{
private:
  /*! Attributes for code generation
   */
  MethodCode  m_code; 
  bool   m_isroot; //!< If root is set 
  bool   m_must_compile; //!< Whether we must compile main method and it's references
  bool   m_compile_main; //!< Whether we should compile main method
  /*! Performs argument check
   */
  void performArgCheck(ParentData * data);

  /*! Whether method uses predefines signature
   */
  bool m_predefined_signature;
  /*! Sets a predefined class name
   */
  std::string m_predefined_classname;
  /*! Sets a predefined method name
   */
  std::string m_predefined_methname;
  /*! Sets a predefines method descriptor 
   */
  std::string m_predefined_descriptor;
public:
  /*! A class,from which was inherited this method (for determining precursor)
   */
  std::string m_class_from_which_inherited;
  /*! Owner class name
   */
  std::string m_classname;
  /*! Clients
  */
  std::vector<std::string>  m_clients;
 /*! Return type (or variable type)
  */
  ClassTypeNode * m_return_type;
 /*! Routine
  */
  Compound   *    m_routine;
 /*! Method type
  */
  int  m_type;
  /*! Reserved local variables
   */
  int  m_reserved_local_vars;
  /*! Real name of method
   */
  std::string m_realname;
  std::vector<ArgEntry> m_formal_args;
  std::vector<ArgEntry> m_local_vars;

  FeatureSpecName *     m_node;

  std::vector<std::string>  m_overriden_methodnames;
  std::vector<Method>       m_overriden_methods;


  
public:
	   inline Method() { m_isroot=false; m_reserved_local_vars=0; m_predefined_signature=false; m_must_compile=true; m_compile_main=true;}
	   /*! Reserves a local variable in method. Used by ManifestArray to produce temporary place to build an array
	    */
	   int reserveLocalVar() { m_reserved_local_vars++; return  m_formal_args.size()+m_local_vars.size()+m_reserved_local_vars-1; }
	   /*! Returns formal arguments count
	    */
	   inline int formalArgumentsCount() const {
	    return m_formal_args.size();
	   }
	   /*! Returns formal argument type by index
	    */
	   inline ClassTypeNode * getFormalArgumentTypeByIndex(int index) {
		return m_formal_args[index].Type;
	   }
	   /*! Returns owner class name
	    */
	   inline const std::string & ownerClass() const { return m_classname; }
	   /*! Sets an entity list data
		   \param[in] formal formal arguments
		   \param[in] local  local  arguments
		   \param[in] data   semantic data
	    */
	   void setEntityLists(const std::vector<ArgEntry> & formal, 
						   const std::vector<ArgEntry> & local
						  );

	   inline void setNode(FeatureSpecName * node)
		{
			m_node=node;
		}
		inline FeatureSpecName * node() const
		{
			return m_node;
		}

		inline void overrideMethod(Method * meth,const std::string & name)
		{
			m_overriden_methods.push_back(*meth);
			m_overriden_methodnames.push_back(name);
		}
		inline void setLastOverridenFrom(const std::string & className)
		{
		  m_overriden_methods[m_overriden_methods.size()-1].m_class_from_which_inherited=className;
		}
		bool overridesMethod(const std::string & classname, const std::string & methodname);
		/**
		    Has following formal args
			\param[in] args
			\param[in] className class name
			\return true if set up
		 */
		bool hasFormalArgSignature(const std::vector<std::string> & args, const std::string & className);
		/** Returns type if method returns something, otherwise null
		 */
		inline ClassTypeNode * returnType()
		{
			if (m_return_type)
			{
				if (m_return_type->fullName()!="VOID")
					return m_return_type;
				else
					return NULL;
			}
			return NULL;
		}
		/** 
		    Marks a root
		 */
		void markAsRoot() {m_isroot=true; }
		/**
		   Returns ability for root
		 */
		bool isRoot() { return m_isroot; }
		/** Fixes clients of string
			\param[in] class, that supposed to be client
		 */
		inline void fixClients(const std::string & className) { ::fixClients(m_clients,className); }

		/** Returns clients of method
		 */
		const std::vector<std::string> & getClients() const {return m_clients; }
		/** Returns overriden non abstract method (NULL if not found)
		 */
		const Method * getOverridenNonAbstractMethod() const;
		/** Returns a type
		  */
		inline int methodType() const { return m_type; }
		/** Test formal and local arguments for shadowing and other stuff
		  */
		void checkFormalAndLocalVars(ParentData * data);
		/** Seeks for formal argument
			\return -1 if not found
		 */
		int findFormalArg(const std::string & string);
		/** Seeks for local variable
			\return -1 if not found
		 */
		int findLocalVar(const std::string & string);
		/** Returns variable by index
			
		  */
		inline ClassTypeNode * getArgByIndex(int i, bool local=true)
		{
		    if (local)
				return m_local_vars[i].Type;
			else
				return m_formal_args[i].Type;
		}
		/**	Returns a local variable by type for index
		 */
		inline ClassTypeNode * getArgByName(const std::string & name)
		{
			int index=findFormalArg(name);
			if (index!=-1)
				return m_formal_args[index].Type;
			else
			{
				index=findLocalVar(name);
				if (index!=-1)
					return m_local_vars[index].Type;
			}
			return NULL;
		}

		/** Returns a routine for method
		 */
		inline Compound * routine() { return m_routine; }
		/**  Returns place, where it is declared
		  */
		inline FeatureSpecName * declarationPlace() { return  m_node; }
		/** Sets a routine
		 */
		inline void setRoutine(Compound * r) { m_routine=r;}
		/** Checks, whether method is available from class
		 */
		bool isAvailable(const std::string & className, SemanticVisitorData * data);
		/*! Returns a number of local variable by name
			\param[in] name  name
			\return -1 if not found
		 */
		inline int getLocalNumberByName(const std::string & name)
		{
			int index=findLocalVar(name);
			if (index!=-1)
			{
				return m_formal_args.size()+index;
			}
			index=findFormalArg(name);
			return index;
		}

		/*!	Returns a compilable name of method
		 */
		inline std::string getCompilableName()
		{
			hst::string classData=m_classname.c_str();
			classData.removeLastOccurence("[","]");
			classData<<m_realname.c_str();
			return classData.data();
		}
		/*! Returns a name of owner class, that can be compile by java
		 */
		std::string ownerName();
		/*! Predefines a method signature
			\param[in] className used class name
			\param[in] methodname used method name
			\param[in] descriptor used descriptor
		 */
		void predefineSignature(const std::string & className, const std::string & methodname,const std::string & descriptor);
		/** Returns a real name of field
		 */
		inline const std::string & realName() const {
			return m_realname;
		}
		/**
			Returns true if method has a precursor, named as self
		 */
		bool hasPrecursor(Method * meth);
		/** Returns a common name for method
			\param[out] name name of method
			\param[out] descriptor used descriptor of method
		 */
		void getCommonCompilableSignature(std::string & name, std::string & descriptor);
		/** Returns a common name for method
			\param[out] name name of method
			\param[out] descriptor used descriptor of method
		 */
		void getFullCompilableSignature(std::string & name, std::string & descriptor);
		/** Returns a method ref info
			\param[out] classname used class name
			\param[out] name  name of method
			\param[out] descriptor used descriptor
		 */
		void getRefInfo(std::string & classname,std::string & name, std::string & descriptor);
		/*! Determines, whether method has a specific arguments
		 */
		bool hasSpecificArguments();
		/*! Returns a total local variables
		 */
		inline unsigned short totalLocalVarsCount()
		{
		  return m_formal_args.size()+m_local_vars.size()+m_reserved_local_vars;
		}
		/*! Returns a total formal args
		 */
		inline unsigned short totalFormalArgs()
		{
			return m_formal_args.size();
		}
		/*! Returns a result value index
		 */
		inline unsigned short getResultVariableIndex()
		{
			return getLocalNumberByName("RESULT");
		}
		/*! Returns an attributes for code generation
		 */
		inline MethodCode & codeAttrs() {
			return m_code;
		}


		/*! Whether we should compile this method
		 */
		inline bool shouldCompile() {
			return m_must_compile;
		}

		/*! If we should not compile method it toggles a flag
		 */
		inline void dontCompile() { m_must_compile=false;}
		/*! If we should compile method it toggles a flag
		 */
		inline void mustCompile() { m_must_compile=true;}

		/*! Whether we should compile main method
		 */
		inline bool shouldCompileMainMethod() {
			return m_compile_main;
		}
		/*! Sets a method flag as dont compile
		 */
		inline void dontCompileMainMethod() { m_compile_main=false; }
		/*! Sets a method flag as must compile
		 */
		inline void mustCompileMainMethod() { m_compile_main=true; }
};


class MethodSignature
{
 private:
	std::string              returnType;
	std::vector<std::string> formalArgs;
 public:
	MethodSignature(const Method & m);
    bool operator==(const MethodSignature & o) const;

	inline const std::vector<std::string> & formalArgList() const
	{
		return formalArgs;
	}
};


/*! Transoforms an entity list to map, filling errors
 */
std::vector<ArgEntry> linearize(EntityList * list,SemanticVisitorData *  data);

